﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Timers;

namespace Drive.LiveExcelHost
{
    class EventTimer
    {
        public int length { get; set; }

        public int interval { get; set; }

        public int minutes { get; set; }

        /// <summary>
        /// 时间线偏移量
        /// </summary>
        private int offset { get; set; }

        public EventTimer(int minutes)
        {
            this.minutes = minutes;
            //最大支持前后N分钟，N分钟历史，N分钟未来
            //即，2 * N分钟 *60秒*1000毫秒
            //精度10毫秒
            interval = 10;
            //圆周长度Length，2 * N * 60 * 1000 /10 
            timeLine = new bool[2 * minutes * 60 * 1000 / interval];
            eventId = new Guid[2 * minutes * 60 * 1000 / interval];
            offset = minutes * 60 * 1000;
            timer = new Timer(interval);
            timer.Elapsed += Timer_Elapsed;
        }

        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            //当时间间隔走动interval
            //偏移量+1
            offset++;
            timeLine[offset] = true;

            resetPast(offset);
            resetFuture(offset);

            //如果到达结尾，则从头开始
            if (offset == timeLine.Length - 1)
            {
                offset = -1;
            }
        }

        private void resetPast(int offset)
        {
            var position = offset - 1;
            if (position < 0)
                position = timeLine.Length - 1;
            timeLine[position] = false;
            eventId[position] = Guid.NewGuid();
        }
        private void resetFuture(int offset)
        {
            var position = offset + 1;
            if (position == timeLine.Length)
                position = 0;
            timeLine[position] = false;
            eventId[position] = Guid.NewGuid();
        }

        public Timer timer = new Timer(100);

        /// <summary>
        /// 在时间线上，过期的重置为false，事件发生的置为true
        /// </summary>
        bool[] timeLine;

        Guid[] eventId { get; set; }

        public void WaitFuture(int millilseconds)
        {
            var steps = (int)Math.Floor(millilseconds / interval * 1.0);
            if (steps > timeLine.Length / 2 - 1)
            {
                throw new IndexOutOfRangeException("超限");
            }
            var position = offset + steps;
            if (position > timeLine.Length - 1)
            {
                position = timeLine.Length - 1 - position;
            }
            var id = eventId[position] = Guid.NewGuid();
            while (eventId[position] == id)
            {
                if (timeLine[position])
                    break;
                
                Thread.SpinWait(1024);
            }
        }
    }
}
